package main

import (
	"flag"
	"fmt"
	"github.com/fsnotify/fsnotify"
	"github.com/mitchellh/mapstructure"
	"github.com/sevlyar/go-daemon"
	"github.com/spf13/viper"
	"hotfix/utils"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"time"
)

// MakeSureDirExist
func _(fileName string) error {
	dirName := filepath.Dir(fileName)
	if _, err := os.Stat(dirName); os.IsNotExist(err) {
		if err = os.MkdirAll(dirName, os.ModePerm); err != nil {
			return err
		}
		return nil
	} else {
		return err
	}
}

var app = utils.App{}

/**
-flag // 只支持bool类型(且值为 true)
-flag=x // 支持所有类型
-flag x // 只支持非bool类型
*/
var runGame = flag.String("g", "", "自动更新游戏名称(请创建对应的 yaml 文件) 如 pdk")
var runTime = flag.String("t", "1-06:30", "自动更新执行时间(天-时:分) 如 0-18:30")
var runBuild = flag.Bool("b", true, "自动拉取编译链接(跳过执行 -b=false)") // -b=false

func main() {
	flag.Parse()

	if runtime.GOOS != `windows` {
		// 切换当前目录到可执行文件所在目录
		pwd := filepath.Dir(os.Args[0])
		if absDir, err := filepath.Abs(pwd); err != nil {
			log.Fatalln(">>> 获取应用程序绝对路径失败:", err)
		} else {
			if err := os.Chdir(absDir); err != nil {
				log.Fatalln(">>> 切换应用程序工作目录失败:", err)
			}
		}
		_ = os.Mkdir("md5", os.ModePerm)
		_ = os.Mkdir("ps", os.ModePerm)
	} else {
		app.Gitlab.Username = utils.CFBEncrypt("shaofeng")
		app.Gitlab.Password = utils.CFBEncrypt("xiuxiu123")
		app.Hotfix.WebHook = utils.CFBEncrypt("https://oapi.dingtalk.com/robot/send?access_token=adc62f81caf3153346ddcc056eaadf3f6777919d2c571e7fab7d64e0050ec586")
	}

	// 读取本可执行文件配置
	app.Yaml = viper.New()
	app.Yaml.SetConfigFile(utils.DefaultConfigFile)
	err := app.Yaml.ReadInConfig()
	if err != nil {
		log.Fatalln(">>> 读取配置文件失败 ->", err)
	}

	app.Yaml.WatchConfig()
	app.Yaml.OnConfigChange(func(e fsnotify.Event) {
	})

	opt := func(config *mapstructure.DecoderConfig) {
		config.TagName = "yaml"
		// do anything your like
	}
	if err := app.Yaml.Unmarshal(&app, opt); err != nil {
		log.Fatalln(">>> 解析配置文件失败 ->", err)
	}

	var b64str string
	if len(*runGame) > 0 && len(*runTime) > 0 {
		app.Hotfix.CronGame = *runGame
		app.Hotfix.CronTime = *runTime

		now := time.Now()
		var day, hour, min time.Duration = 1, 6, 30 // 默认翌日六点半🕡
		_, _ = fmt.Sscanf(app.Hotfix.CronTime, "%d-%d:%d", &day, &hour, &min)
		task := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
		task = task.Add(time.Hour*(24*day+hour) + time.Minute*min)

		app.Hotfix.CronSeconds = time.Duration(task.Unix() - now.Unix())
		app.Hotfix.CronTime = task.Format(utils.LayoutChangsha)
		if app.Hotfix.CronSeconds < 0 {
			log.Fatalln(">>> 请重新设置执行时间:", app.Hotfix.CronTime)
		}

		if *runBuild != false {
			// 编译程序
			path := filepath.Join(app.Gitlab.Path, app.Hotfix.CronGame)
			if utils.PathExist(path) {
				app.Gitlab.Pull()
				(&utils.Cmake{Path: path}).Build()
			}
		}
		b64str = app.Hotfix.Init()
	}

	// kill `cat ps/pdk.pid`
	pidPath := filepath.Join("ps", app.Hotfix.CronGame+".pid")
	logPath := filepath.Join("ps", app.Hotfix.CronGame+".log")
	arg0 := fmt.Sprintf("[go-daemon hotfix %s]", app.Hotfix.CronGame)
	context := &daemon.Context{
		PidFileName: pidPath,
		PidFilePerm: 0644,
		LogFileName: logPath,
		LogFilePerm: 0640,
		WorkDir:     "./",
		Umask:       027,
		Args:        []string{arg0, b64str},
	}
	app.Hotfix.Context = context

	if runtime.GOOS != `windows` {
		reborn, err := context.Reborn()
		if err != nil {
			log.Fatalln(">>> 启动守护进程失败:", err)
		}
		if reborn != nil {
			if len(b64str) == 0 {
				flag.Usage()
			}
			return
		} else {
			b64str = context.Args[1]
		}
	}

	defer func() { _ = context.Release() }()

	// 子进程中的"参数"必须在启动守护进程之后才会有值
	if len(b64str) == 0 {
		return
	}

	app.Hotfix.Run(&app.Mysql, b64str)
}
